from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput


from kivy.properties import ObjectProperty, AliasProperty, ListProperty, BooleanProperty, NumericProperty, StringProperty, BoundedNumericProperty


class NumericInput(TextInput):
    value = NumericProperty(0)
    #value = BoundedNumericProperty(0, min=None, max=None)
    step  = NumericProperty(1)

    integer = BooleanProperty(False)
    
    
    numeric_type = float
    allowed_text = '0123456789.-' 

    _changing_v_or_t = False
    def __init__(self, **kargs):
        super(NumericInput, self).__init__(**kargs)
        self.allowed_keys = self.interesting_keys.keys()
        self.allowed_keys += [ 27 ] #escape 

    def on_integer(self, i, v):
        if v:
            self.numeric_type = int
            self.allowed_text = '0123456789-' 
        else:
            numeric_type = float
            allowed_text = '0123456789.-' 
            
    def _keyboard_on_key_down(self, window, keycode, text, modifiers):
        key, key_str = keycode
        hasmodifier = modifiers == ['ctrl'] or (modifiers == ['meta'])
        if key in self.allowed_keys or text in self.allowed_text or hasmodifier:
            return super(NumericInput,self)._keyboard_on_key_down( window, keycode, text, modifiers)
        

    def on_text(self, i, v):
        if self._changing_v_or_t :
            self._changing_v_or_t = False
            return
        if v == '': v=0
        elif v == '-': v=0
        try:
            numv = self.numeric_type(v)
            self._changing_v_or_t = numv!=self.value #True
            self.value = numv
        except:
            print 'except ', self.value
            self.text = str(self.value)

    def on_value(self,i,v):
        if self._changing_v_or_t:
            self._changing_v_or_t = False
        else:
            self._changing_v_or_t = True
            self.text = str(self.value)

            
    def increase(self):
        self.value += self.step

    def decrease(self):
        self.value -= self.step


class _alias_guard:
    free = True
def property_alias(o1 , o2 , pname):
    guard = _alias_guard()
    def o1_changed(i,v):
        #print 'o1_changed ', i, v
        if guard.free:
            guard.free = False
            setattr( o2, pname, v)
        else:
            guard.free = True

    def o2_changed(i,v):
        #print 'o2_changed ', i, v
        if guard.free:
            guard.free = False
            setattr( o1, pname, v)
        else:
            guard.free = True

    o2.bind( **{pname : o2_changed})        
    o1.bind( **{pname : o1_changed})

    
class SpinBox(Widget):
    txtinput = ObjectProperty(None)

    background_color = ListProperty([])
    pressed = StringProperty('none')

    button_width = NumericProperty(16)
    button_height = NumericProperty(16)

    #value = AliasProperty(_get_value, _set_value)
    value = NumericProperty(0)
    #value = BoundedNumericProperty(0, min=None, max=None)
    step  = NumericProperty(1)

    integer = BooleanProperty(False)

    up_button_icon_src = StringProperty('atlas://data/images/defaulttheme/tree_opened')


    def __init__(self, **kargs):
        super(SpinBox,self).__init__(**kargs)
        property_alias(self, self.txtinput, 'value')
        property_alias(self, self.txtinput, 'step')
        property_alias(self, self.txtinput, 'integer')                

        # awfull trick to get props in sync automatically.
        self.value +=1
        self.value -=1
        
        self.txtinput.bind(on_text_validate=self.on_input_validated)

        self.register_event_type('on_input_validated')

    def on_input_validated(self, *l):
        pass

    def set_focus(self, *l):
        self.txtinput.focus = True
    
    def on_touch_down(self, touch):
        if not self.collide_point(touch.x, touch.y):
            return False
        if touch.x < self.right - self.button_width:
            self.txtinput.dispatch('on_touch_down', touch)
            return False        
        if self in touch.ud:
            return False
        touch.grab(self)
        touch.ud[self] = True
        self.pressed = 'up' if touch.y > self.y+self.button_height else 'down'

        return True

    def on_touch_move(self, touch):
        if touch.x < self.right - self.button_width:
            return False        
        return self in touch.ud
   
    def on_touch_up(self, touch):
        if touch.x < self.right - self.button_width:
            self.txtinput.dispatch('on_touch_down', touch)            
            return False                
        if touch.grab_current is not self:
            return
        assert(self in touch.ud)
        touch.ungrab(self)
        if self.pressed == 'down':
            self.txtinput.decrease()
        else:
            self.txtinput.increase()
        self.pressed = 'none'
        return True
    
    ## def on_background_color(self, *l):
    ##     print 'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee changing color ',l
    

from kivy.factory import Factory
for cls in [SpinBox, NumericInput]:
    Factory.register(cls.__name__, cls=cls)

from kivy.lang import Builder
from os.path import dirname, join
Builder.load_file(join( dirname(__file__) , 'spinbox.kv'  ) )

